#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <unistd.h>
#include <sys/wait.h>
#include "Task.hpp"

// 信道--先描述
class Channel
{
public:
	Channel(int wfd, pid_t subid)
		: _wfd(wfd), _subid(subid)
	{
		_name = "channel-" + std::to_string(_wfd) + "-" + std::to_string(_subid);
	}
	~Channel() {}

	// 写入任务码，发给子进程
	void Send(int code)
	{
		int n = write(_wfd, &code, sizeof(code));
		(void)n;
	}

	// 关闭写端
	void Close()
	{
		close(_wfd);
	}

	// 等待子进程结束
	void Wait()
	{
		pid_t rid = waitpid(_subid, nullptr, 0);
		(void)rid;
	}

	int GetFd() { return _wfd; }
	pid_t GetSubid() { return _subid; }
	std::string GetName() { return _name; }

private:
	int _wfd;		   // 写端
	pid_t _subid;	   // 子进程id
	std::string _name; // 信道名称
};

// 管理信道--再组织
class ChannelManager
{
public:
	ChannelManager()
		: _next(0)
	{
	}

	// 新增信道
	void Insert(int wfd, pid_t subid)
	{
		_channels.emplace_back(wfd, subid);
	}

	// 选择信道
	Channel &Select()
	{
		auto &c = _channels[_next++];
		_next %= _channels.size();
		return c;
	}

	// 打印
	void PrintChannel()
	{
		for (auto &c : _channels)
		{
			std::cout << c.GetName() << std::endl;
		}
	}

	// 关闭所有子进程
	void StopSubProcess()
	{
		for (auto &channel : _channels)
		{
			channel.Close();
			std::cout << "关闭: " << channel.GetName() << std::endl;
		}
	}

	// 等待并回收所有子进程
	void WaitSubProcess()
	{
		for (auto &channel : _channels)
		{
			channel.Wait();
			std::cout << "回收: " << channel.GetName() << std::endl;
		}
	}

	~ChannelManager() {}

private:
	std::vector<Channel> _channels; // 管理信道
	int _next;						// 用于轮询选择信道
};

const int gdefaultnum = 5;

// 进程池
class ProcessPool
{
public:
	ProcessPool(int num = gdefaultnum)
		: _process_num(num)
	{
		_tm.Register(PrintLog);
		_tm.Register(DownLoad);
		_tm.Register(Upload);
	}

	// 子进程工作
	void Work(int rfd)
	{
		while (true)
		{
			int code = 0;
			int n = read(rfd, &code, sizeof(code));
			if (n > 0)
			{
				if (n != sizeof(code))
					continue;
				std::cout << "子进程[" << getpid() << "]" << "收到一个任务码: " << code << std::endl;
				_tm.Execute(code);
			}
			else if (n == 0)
			{
				std::cout << "子进程[" << getpid() << "]退出" << std::endl;
				break;
			}
			else
			{
				std::cout << "读取错误" << std::endl;
				break;
			}
		}
	}

	// 创建进程池
	bool Start()
	{
		for (int i = 0; i < _process_num; ++i)
		{
			// 1.创建管道
			int pipefd[2] = {0};
			int n = pipe(pipefd);
			if (n != 0)
				return false;

			// 2.创建子进程
			pid_t subid = fork();
			if (subid < 0)
				return false;
			else if (subid == 0)
			{
				// 子进程
				// 3.关闭不需要的文件描述符
				close(pipefd[1]); // 关闭写端
				Work(pipefd[0]);
				close(pipefd[0]); // 结束关闭管道
				exit(0);
			}
			else
			{
				// 父进程
				// 3.关闭不需要的文件描述符
				close(pipefd[0]);			  // 关闭读端
				_cm.Insert(pipefd[1], subid); // 将新管道管理起来
			}
		}
		return true;
	}

	void Run()
	{
		// 1.选择一个任务
		int taskcode = _tm.Code();

		// 2.选择信道(子进程)，需负载均衡的选择一个子进程
		auto &c = _cm.Select();
		std::cout << "选择一个子进程: " << c.GetName() << std::endl;

		// 3.发送任务码
		c.Send(taskcode);
		std::cout << "发送一个任务码: " << taskcode << std::endl;
	}

	// 测试
	void Debug()
	{
		_cm.PrintChannel();
	}

	// 停止
	void Stop()
	{
		// 1.关闭所有父进程的wfd
		_cm.StopSubProcess();

		// 2.等待所有子进程结束
		_cm.WaitSubProcess();
	}

	~ProcessPool() {}

private:
	ChannelManager _cm; // 管理信道
	int _process_num;	// 进程数
	TaskManager _tm;	// 任务管理器
};